﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using IniTechCaash.Domain.Entities;
using IniTechCaash.Domain.EntityFramework;
using IniTechCaash.WebApplication.Models;
using System.Threading.Tasks;

namespace IniTechCaash.WebApplication.Controllers
{
    public class FinanceAccountController : Controller
    {
        CaashContext db;

        public FinanceAccountController()
        {
            db = new CaashContext();
        }

        [Authorize(Roles = "Admin, Manager, User")]
        public ActionResult BalanceSheet()
        {
            var accounts = db.Accounts.ToList();
            List<FinanceAccountDetailsViewModel> models = new List<FinanceAccountDetailsViewModel>(accounts.Count);
            foreach (var a in accounts)
                models.Add(new FinanceAccountDetailsViewModel(a));

            return View(models);
        }

        [Authorize(Roles = "Admin")]
        public ActionResult Create()
        {
            return View(new FinanceAccountCreateViewModel());
        }

        [Authorize(Roles = "Admin")]
        [HttpPost]
        public ActionResult Create(FinanceAccountCreateViewModel model)
        {
            if (db.Accounts.FirstOrDefault(a => a.Name == model.Name) != null)
                ModelState.AddModelError("Name", "New Account must have a distinct Name.");
            if (!ModelState.IsValid)
            {
                ModelState.AddModelError("", "Invalid model.");
                return View(model);
            }

            Account account = model.GetAccount(User.Identity.Name);

            AccountType[] types = account.Type.GetGeneralAccountType().GetAccountTypes();
            int numberIndex = db.Accounts.Where(a => types.Contains(a.Type)).Count();

            string number = numberIndex.ToString();
            while (number.Length < 8)
                number = "0" + number;
            number = account.Type.GetNumberPrefix().ToString() + number;
            account.Number = number;

            account.CreatedBy = account.LastModifiedBy = User.Identity.Name;
            account.CreatedDate = account.LastModifiedDate = DateTime.Now;
            db.Accounts.Add(account);
            db.SaveChanges();

            return RedirectToAction("Details", new { id = account.Id });
        }

        [Authorize(Roles = "Admin, Manager, User")]
        public ActionResult Details(int id)
        {
            var account = db.Accounts.First(a => a.Id == id);
            account.JournalEntryLines = account.JournalEntryLines.Where(jel => jel.JournalEntry.IsPosted).OrderByDescending(jel => jel.JournalEntry.DatePosted).ToList();
            var model = new FinanceAccountDetailsViewModel(account);

            var activityLogs = db.ActivityLogs.Where(al => al.ObjectReferenceType == "Account" && al.ObjectReferenceId == account.Id);
            model.ActivityLogs = activityLogs.ToList();
            model.ActivityLogs.Insert(0, new ActivityLog
            {
                CreatedBy = model.CreatedBy,
                LogDate = model.CreatedDate,
                Message = "Created.",
                ObjectReferenceId = model.Id,
                ObjectReferenceType = "Account",
            });

            return View(model);
        }

        [Authorize(Roles = "Admin")]
        public ActionResult Edit(int id)
        {
            var account = db.Accounts.First(a => a.Id == id);
            var model = new FinanceAccountEditViewModel(account);
            return View(model);
        }

        [Authorize(Roles = "Admin")]
        [HttpPost]
        public ActionResult Edit(FinanceAccountEditViewModel model)
        {
            if (db.Accounts.Where(a => a.Name == model.Name).Take(2).Count() > 1)
                ModelState.AddModelError("Name", "New Account must have a distinct Name.");
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            var account = db.Accounts.First(a => a.Id == model.Id);
            account = model.GetAccount(account, User.Identity.Name);

            account.LastModifiedBy = User.Identity.Name;
            account.LastModifiedDate = DateTime.Now;

            db.Entry<Account>(account).State = EntityState.Modified;
            db.SaveChanges();

            ActivityLog log = new ActivityLog
            {
                CreatedBy = User.Identity.Name,
                LogDate = DateTime.Now,
                Message = "Modified.",
                ObjectReferenceId = account.Id,
                ObjectReferenceType = "Account",
            };
            db.ActivityLogs.Add(log);
            db.Entry<ActivityLog>(log).State = EntityState.Added;
            db.SaveChanges();

            return RedirectToAction("Details", new { id = account.Id });
        }

        [Authorize(Roles = "Admin, Manager, User")]
        public ActionResult IncomeStatement()
        {
            var accounts = db.Accounts.ToList();
            List<FinanceAccountDetailsViewModel> models = new List<FinanceAccountDetailsViewModel>(accounts.Count);
            foreach (var a in accounts)
                models.Add(new FinanceAccountDetailsViewModel(a));

            return View(models);
        }

        [Authorize(Roles = "Admin, Manager, User")]
        public ActionResult Index()
        {
            List<FinanceAccountDetailsViewModel> models = new List<FinanceAccountDetailsViewModel>();
            var accounts = db.Accounts;
            foreach (var a in accounts)
                models.Add(new FinanceAccountDetailsViewModel(a));
            models = models.OrderBy(m => m.Type).OrderBy(m => m.Number).ToList();

            return View(models);
        }

        [Authorize(Roles = "Admin, Manager, User")]
        public ActionResult Ratios()
        {
            var accounts = db.Accounts.ToList();
            List<FinanceAccountDetailsViewModel> models = new List<FinanceAccountDetailsViewModel>(accounts.Count);
            foreach (var a in accounts)
                models.Add(new FinanceAccountDetailsViewModel(a));

            return View(models);
        }

        [Authorize(Roles = "Admin, Manager, User")]
        public ActionResult TrialBalance()
        {
            List<FinanceAccountDetailsViewModel> models = new List<FinanceAccountDetailsViewModel>();
            var accounts = db.Accounts.Where(a => a.Balance != 0.00m);
            foreach (var a in accounts)
                models.Add(new FinanceAccountDetailsViewModel(a));
            models = models.OrderByDescending(m => m.Type.GetNormalSide()).ThenBy(m => m.Type).ThenBy(m => m.Number).ToList();

            return View(models);
        }
	}
}